/**
 * 自定义表单组件
 */

import { Form, Input, Button, Select, InputNumber, DatePicker, Checkbox, Space } from 'antd';
import { useMemo, useRef, useEffect, useImperativeHandle, forwardRef, useState } from 'react';
import { TS, CS, SS, CSS } from 'com';
import { DeleteOutlined, SearchOutlined } from '@ant-design/icons';
import Upload from './components/Upload';
import './index.scss';
import dayjs from 'dayjs';
const { Item } = Form;
const { toString } = Object.prototype;
const { RangePicker } = DatePicker;

/**
 * TS项
 * @param {*} param0 
 */
const TSItem = ({ value, multi, onChange, all, clear, style }) => {
    const [name, setName] = useState('');
    const [options, setOptions] = useState([]);
    const [keys, setKeys] = useState([]);
    const com = useRef();
    useEffect(() => {
        if (value instanceof Array) {
            for (const item of value) {
                if (!(item instanceof Object)) continue;
                //如果传过来的数据不包含在已选中的key中，那么久让他选中
                if (!keys.includes(item.id)) {
                    keys.push(item.id);
                    setKeys([...keys]);
                }
                //如果传过来的数据不存在options中，就添加进去
                if (!options.some(c => c.value === item.id)) {
                    options.push({ label: item.name, value: item.id });
                    setOptions([...options]);
                }
            }
        }
        else if (toString.call(value) === '[object Object]') {
            onChange(value.id);
            setName(value.name);
        }
        else if (null === value || undefined === value) {
            setName('');
        }
    }, [value]);

    /**
     * 
     * @param {*} keys 选中的keys
     * @returns 
     */
    const change = keys => setKeys(keys);

    useEffect(() => {
        undefined !== value && multi && onChange(keys);
    }, [keys]);


    return <>
        <TS ref={com} multi={multi} all={all} onFinish={obj => onChange(obj)} />
        {multi ? <Space.Compact size={0} className="select"><Select allowClear={clear} value={keys} onChange={change} options={options} mode="multiple" style={style} /><Button type="primary" onClick={() => com.current.show()} icon={<SearchOutlined />} /></Space.Compact> : <Input readOnly onClick={() => com.current.show()} style={style} value={name} addonAfter={clear && value && <DeleteOutlined onClick={() => onChange(undefined)} />} />}
    </>
}

/**
 * 其他组件的项
 * @param {*} param0 
 */
const OtherItem = ({ value, tag, onChange, clear, style }) => {
    const [name, setName] = useState('');
    const com = useRef();
    useEffect(() => {
        if (toString.call(value) === '[object Object]') {
            onChange(value.id);
            setName(value.name);
        }
        else if (null === value || undefined === value) {
            setName('');
        }
    }, [value]);
    return <>
        {tag === 'cs' ? <CS ref={com} onFinish={obj => onChange(obj)} /> : <SS ref={com} onFinish={obj => onChange(obj)} />}
        <Input readOnly style={style} onClick={() => com.current.show()} value={name} addonAfter={clear && value && <DeleteOutlined onClick={() => onChange(undefined)} />} />
    </>
}

/**
 * 课程选择器的项
 * @param {*} param0 
 */
const CSSItem = ({ value, onChange, clear, style, isSelf, attrs }) => {
    const [name, setName] = useState('');
    const com = useRef();
    useEffect(() => {
        if (toString.call(value) === '[object Object]') {
            onChange(value.id);
            const { from_date, end_date } = value;
            setName(`${dayjs(from_date).format('YYYY-MM-DD HH:mm:ss')}至${dayjs(end_date).format('YYYY-MM-DD HH:mm:ss')}`);
        }
        else if (null === value || undefined === value) {
            setName('');
        }
    }, [value]);
    return <>
        <CSS {...attrs} isSelf={isSelf} ref={com} onFinish={obj => onChange(obj)} />
        <Input readOnly style={style} onClick={() => com.current.show()} value={name} addonAfter={clear && value && <DeleteOutlined onClick={() => onChange(undefined)} />} />
    </>
}

/**
 * 自定义错误信息
 */
const defaultValidateMessages = {
    deafult: '${label}不是一个有效的${type}',
    required: "${label}不能为空",
    whitespace: "${label}不能为空",
    string: {
        len: "${label}长度必须为${len}位",
        min: "${label}最小长度为${min}位",
        max: "${label}最大长度为${max}位",
        range: "${label}的长度为${min}-${max}位",
    },
    number: {
        len: "${label}长度必须为${len}位",
        min: "${label}最小为${min}",
        max: "${label}最大为${max}",
        range: "${label}必须在${min}-${max}之间",
    }
};

export default forwardRef((props, ref) => {
    const { options, attrs, size = 'large', onFinish, values, lw } = props;
    /**
     * form引用
     */
    const form = useRef();
    /**
     * 表单配置项
     */
    const _options = useMemo(() => {
        const items = [];
        for (const key in options) {
            if (Object.hasOwnProperty.call(options, key)) {
                const item = options[key];
                const { min, max, ph, title } = item;
                const _item = {
                    name: key,
                    ...item,
                    ph: ph?.replace(/{t}/g, title),
                    tag: item.tag || 'input',
                    rules: item.rules || []
                };
                //是否有required
                item.required && _item.rules.unshift({ required: true });
                //是否有max
                if (min && max) {
                    _item.rules.push({ max, min });
                }
                //是否有min
                else if (min) {
                    _item.rules.push({ min });
                }
                else if (max) {
                    _item.rules.push({ max });
                }

                for (const rule of _item.rules) {
                    if (rule.match) {
                        rule.validator = (r, value) => {
                            const v = form.current.getFieldValue(rule.match);
                            return v === value ? Promise.resolve() : Promise.reject(rule.message);
                        }
                    }
                }

                items.push(_item);
            }
        }
        return items;
    }, [options]);

    useEffect(() => {
        form.current.setFieldsValue(values);
    }, [values]);

    useImperativeHandle(ref, () => ({
        submit: () => form.current?.submit(),
        validateFields: () => form.current?.validateFields()
    }));


    return <Form autoComplete="off" preserve={false} ref={form} onFinish={onFinish} labelCol={undefined !== lw ? { style: { width: lw } } : {}} validateMessages={defaultValidateMessages} size={size} {...attrs}>
        {
            _options.map(c => <Item validateFirst key={c.name} name={c.name} label={c.title} rules={c.rules} valuePropName={c.tag === 'checkbox' ? 'checked' : undefined}>
                {
                    c.tag === 'input' ? <Input placeholder={c.ph} type={c.type} style={c.style} {...c.attrs} maxLength={c.max} /> :
                        c.tag === 'select' ? <Select placeholder={c.ph} style={c.style} {...c.attrs} options={c.values}></Select> :
                            c.tag === 'button' ? <Button onClick={c.click} loading={c.loading} type={c.type || 'primary'} htmlType={c.htmlType} {...c.attrs} style={c.style}>{c.text}</Button> :
                                c.tag === 'number' ? <InputNumber placeholder={c.ph} min={c.min} style={c.style} max={c.max} {...c.attrs} /> :
                                    c.tag === 'date' ? <DatePicker placeholder={c.ph} style={c.style} picker={c.picker} {...c.attrs} /> :
                                        c.tag === 'checkbox' ? <Checkbox /> :
                                            c.tag === 'ts' ? <TSItem multi={c.multi} clear={c.clear} all={c.all} style={c.style} /> :
                                                c.tag === 'cs' || c.tag === 'ss' ? <OtherItem clear={c.clear} style={c.style} tag={c.tag} attrs={c.attrs} /> :
                                                    c.tag === 'upload' ? <Upload attrs={c.attrs} style={c.style} tip={c.tip} size={c.size} type={c.type} /> :
                                                        c.tag === 'dateRange' ? <RangePicker showTime={c.showTime} style={c.style} {...attrs} /> :
                                                            c.tag === 'textArea' ? <Input.TextArea maxLength={c.max} style={c.style} {...attrs}></Input.TextArea> :
                                                                c.tag === 'css' ? <CSSItem isSelf={c.isSelf} style={c.style} clear={c.clear} attrs={c.attrs} /> : null
                }
            </Item>)
        }
    </Form>
})